﻿using Dapper;
using System;
using System.Data;
using System.Linq;
using Ayatta.Contract.Domain;
using System.Collections.Generic;
using Ayatta.Contract.Component;

namespace Ayatta.Service.Extension
{
    public static class DapperExtension
    {
        public static IEnumerable<TReturn> Query<TFirst, TSecond, TReturn>(this IDbConnection connection, SqlBuilder.Template template, Func<TFirst, TSecond, TReturn> func) where TFirst : IEntity where TSecond:IEntity where TReturn:TFirst
        {
            return connection.Query(template.RawSql, func, template.Parameters);
        }
        public static PagedList<T> PagedQuery<T>(this IDbConnection connection, SqlBuilder.Template template) where T : IEntity
        {
            int count;
            var source = new List<T>();
            using (var multiple = connection.QueryMultiple(template))
            {
                count = multiple.Read<int>().FirstOrDefault();
                if (count > 0)
                {
                    source = multiple.Read<T>().ToList();
                }
            }
            return new PagedList<T> { Data = source, Total = count };
        }
        public static PagedList<TFirst> ToPagedList<TFirst, TSecond, TKey>(this SqlMapper.GridReader reader, Func<TFirst, TKey> firstKey, Func<TSecond, TKey> secondKey, Action<TFirst, IEnumerable<TSecond>> addChildren)where TFirst : IEntity where TSecond : IEntity 
        {
            var source = new List<TFirst>();
            var count = reader.Read<int>().FirstOrDefault();
            if (count > 0)
            {
                source = reader.Read<TFirst>().ToList();
                var childMap = reader
                    .Read<TSecond>()
                    .GroupBy(secondKey)
                    .ToDictionary(g => g.Key, g => g.AsEnumerable());

                foreach (var item in source)
                {
                    IEnumerable<TSecond> children;
                    if (childMap.TryGetValue(firstKey(item), out children))
                    {
                        addChildren(item, children);
                    }
                }
            }
            return new PagedList<TFirst>(source, count);
        }
    }
}